package de.recipeminer.tools;

import com.google.common.base.Optional;
import org.apache.log4j.Logger;

import java.io.*;
import java.util.Arrays;
import java.util.regex.Pattern;

/**
 * @autor: Markus Ackermann
 */
public class LimitablePrintStream implements Flushable, Closeable {
    private static Logger logger = Logger.getLogger(LimitablePrintStream.class);
    private final PrintStream printStream;
    private int printedLines = 0;
    private int intLineLimit = Integer.MAX_VALUE;
    private Optional<Integer> lineLimit;
    private static Pattern newLines = Pattern.compile("\\n|\\r|\\r\\n");


    public LimitablePrintStream(File file) {
        lineLimit = Optional.absent();
        try {
            printStream = new PrintStream(file);
        } catch (FileNotFoundException e) {
            throw new IllegalStateException("Unable to open file to write output:", e);
        }
    }

    public LimitablePrintStream() {
        lineLimit = Optional.absent();    
        printStream = new PrintStream(System.out);
    }

    public LimitablePrintStream(File file, int limit) {
        lineLimit = Optional.of(limit);
        intLineLimit = lineLimit.orNull();
        try {
            printStream = new PrintStream(file);
        } catch (FileNotFoundException e) {
            throw new IllegalStateException("Unable to open file to write output:", e);
        }
    }

    public LimitablePrintStream(int limit) {
        lineLimit = Optional.of(limit);
        printStream = new PrintStream(System.out);
    }


    public void flush() {
        printStream.flush();
    }

    public void close() {
        printStream.close();
    }

    public void print(String s) {
        if (lineLimit.isPresent()) {
            if (s == null) {
                s = "null";
            }
            String[] linesToPrint = printableLines(s);
            for (String line : linesToPrint) {
                printStream.print(s);
                println();
            }
        } else {
            printStream.print(s);
        }
    }

    public void print(Object obj) {
        if (lineLimit.isPresent()) {
            print(String.valueOf(obj));
        } else {
            printStream.print(obj);
        }
    }

    public void println(String x) {
        if (lineLimit.isPresent()) {
            print(x);
            println();
        } else {
            printStream.println(x);
        }

    }

    public void println(Object x) {
        if (lineLimit.isPresent()) {
            print(x);
            println();
        } else {
            printStream.println(x);
        }
    }

    public void println() {
        printStream.println();
        printedLines++;
    }
    
    
    

    private String[] printableLines(String s) {
        if (lineLimit.isPresent()) {
            String[] allLines = splitInLines(s);
            if (allLines.length <= intLineLimit - printedLines) {
                return allLines;
            } else {
                return Arrays.copyOf(allLines, intLineLimit - printedLines, String[].class);
            }
        }
        return splitInLines(s);
    }

    private String[] splitInLines(String s) {
        return newLines.split(s);
    }
}
